
// Copyright (C) 2009-2011 Luca Piccioni
// 
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//   
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

using System;
using System.Diagnostics;

using Derm.Scene;

namespace Derm.Render
{
	/// <summary>
	/// Perspective camera.
	/// </summary>
	public abstract class PerspectiveCamera : ICamera
	{
		#region Constructors
		
		/// <summary>
		/// PerspectiveCamera constructor.
		/// </summary>
		public PerspectiveCamera() :
			this(45.0f)
		{
			
		}
		
		/// <summary>
		/// PerspectiveCamera constructor.
		/// </summary>
		/// <param name="hFov">
		/// A <see cref="System.Single"/>
		/// </param>
		public PerspectiveCamera(float hFov) :
			this(hFov, 1.0f, 100.0f)
		{

		}
		
		/// <summary>
		/// PerspectiveCamera constructor.
		/// </summary>
		/// <param name="hFov">
		/// A <see cref="System.Single"/>
		/// </param>
		/// <param name="fMin">
		/// A <see cref="System.Single"/>
		/// </param>
		/// <param name="fMax">
		/// A <see cref="System.Single"/>
		/// </param>
		public PerspectiveCamera(float hFov, float fMin, float fMax)
		{
			Debug.Assert(hFov > 0.0f);
			
			// Store horizontal FOV
			VFov = hFov;
			// Store viewing frunstrum ranges
			mMinRange = fMin; mMaxRange = fMax;
		}
		
		#endregion
		
		#region Viewing Fustrum Management
		
		/// <summary>
		/// Vertical field of view property.
		/// </summary>
		public float VFov
		{
			get { return (mVFov); }
			set {
				Debug.Assert(value > 0.0f);
				
				// Store vertical FOV
				mVFov = value;
			}
		}
		
		/// <summary>
		/// Viewing fustrum minimum range.
		/// </summary>
		public float MinRange
		{
			get { return (mMinRange); }
			set {
				Debug.Assert(value >= 0.0f);
				
				// Store viewing fustrum minimum range
				mMinRange = value;
			}
		}
		
		/// <summary>
		/// Viewing fustrum maximum range.
		/// </summary>
		public float MaxRange
		{
			get { return (mMaxRange); }
			set {
				Debug.Assert(value >= 0.0f);
				
				// Store viewing fustrum maximum range
				mMaxRange = value;
			}
		}
		
		/// <summary>
		/// Horizontal field of view.
		/// </summary>
		private float mVFov;
		/// <summary>
		/// Perspective view fustrum minimum range.
		/// </summary>
		private float mMinRange;
		/// <summary>
		/// Perspective view fustrum minimum range.
		/// </summary>
		private float mMaxRange;
		
		#endregion

		#region ICamera Implementation

		/// <summary>
		/// Setup camera projection.
		/// </summary>
		/// <param name="ctx">
		/// A <see cref="RenderContext"/>
		/// </param>
		/// <remarks>
		/// This routine implementation is the characteristic of this class. It defines a perspective
		/// projection, using the camera viewing fustrum.
		/// </remarks>
		public void SetupProjection(RenderContext ctx)
		{
#if false
			ProjectionMatrix mProjection = new ProjectionMatrix();
			float pTop = MinRange * (float)Math.Tan((double)VFov * Math.PI / 360.0);
			float pBottom = -pTop;
			float pRight = pTop * rSurface.Width / rSurface.Height;
			float pLeft = -pRight;

			// Construct projection matrix
			mProjection.SetFustrum(pLeft, pRight, pBottom, pTop, MinRange, MaxRange);
			// Set projection matrix
			ctx.Projection = mProjection;
#endif
		}

		/// <summary>
		/// Apply this perspective view.
		/// </summary>
		/// <param name="ctx">
		/// A <see cref="RenderContext"/>
		/// </param>
		/// <remarks>
		/// Derived classes defines the viewing transformation overriding this routine.
		/// </remarks>
		public abstract void SetupView(RenderContext ctx);



		#endregion
	}
}
